/*************************************************************************/
/*                                                                       */
/*  Copyright (c) 1994 Stanford University                               */
/*                                                                       */
/*  All rights reserved.                                                 */
/*                                                                       */
/*  Permission is given to use, copy, and modify this software for any   */
/*  non-commercial purpose as long as this copyright notice is not       */
/*  removed.  All other uses, including redistribution in whole or in    */
/*  part, are forbidden without prior written permission.                */
/*                                                                       */
/*  This software is provided with absolutely no warranty and no         */
/*  support.                                                             */
/*                                                                       */
/*************************************************************************/


/*
 * NAME
 *	prt - parallel ray tracer
 *
 * SYNOPSIS
 *	prt [options] envfile
 *
 *		-h	Print this usage message.
 *		-a<n>	Enable antialiasing with n subpixels (default = 1).
 *		-m<n>	Request n megabytes of global memory (default = 32).
 *		-p<n>	Run on n processors (default = 1).
 *
 * DESCRIPTION
 *
 * RETURNS
 *	PRT returns an exit code of 0 to the OS for successful operation; it
 *	returns a non-zero exit code (usually 1) if any type of error occurs.
 *
 * EXAMPLES
 *	To ray trace cube.env on 1 processor and default global memory size:
 *
 *		prt cube.env
 *
 *	To ray trace car.env on 4 processors and 72MB of global memory:
 *
 *		prt -p4 -m72 car.env
 *
 * FILES
 *
 * SEE ALSO
 *
 * DIAGNOSTICS
 *	All error messages take the form:
 *
 *	prt: Text of the error message.
 *
 *	All possible error messages are listed below, including the potential
 *	cause of the error, and the corrective action, if any.
 *
 *	FATAL ERRORS
 *		Invalid option '%c'.
 *			The command line included an option which was not
 *			recognized.  Check your command line syntax, remove
 *			the offending option, and try again.
 *
 *		Cannot open file "filename".
 *			The specified file could not be found, or some other
 *			OS error prevented it from being opened.  Check your
 *			typing and try again.
 *
 *		Cannot allocate local memory.
 *			malloc() failed for some reason.
 *
 *		Cannot allocate global memory.
 *			valloc(); failed for some reason.
 *
 *		Valid range for #processors is [1, %ld].
 *			Do not exceed the ranges shown by the message.
 *
 */

#define MAIN	     /* indicate to rt.H that we need main_env for this file*/
#define VERSION 	"1.00"


#include <stdio.h>
#include <math.h>
#include "rt.h"
#include "utilities.h"

#include "pool_notify.h"
//#include <dsplink.h>


//CHAR	*ProgName     = "RAYTRACE";          /* The program name.                 */
INT	nprocs	      = 1;		/* The number of processors to use.  */
INT	MaxGlobMem    = 32;		/* Maximum global memory needed (MB).*/
//INT	NumSubRays    = 1;		/* Number of subpixel samples to calc*/
INT dostats = 0;

INT	TraversalType;
INT	bundlex, bundley;		/* Bundle sizes for workpools.	     */
INT	blockx, blocky; 		/* Block sizes for workpools.	     */

BOOL	GeoFile;			/* TRUE if geometry file name found. */
BOOL	PicFile;			/* TRUE if picture file name found.  */
BOOL	ModelNorm;			/* TRUE if model must be normalized. */
BOOL	ModelTransform; 		/* TRUE if model transform present.  */
BOOL	AntiAlias;			/* TRUE if antialiasing enabled.     */

VIEW	View;				/* Viewing parameters.		     */
DISPLAY Display;			/* Display parameters.		     */
LIGHT	*lights;			/* Ptr to light list.		     */
INT	nlights;			/* Number of lights in scene.	     */
GMEM	*gm;				/* Ptr to global memory structure.   */
GRID	*world_level_grid;		/* Zero level grid pointer.	     */

INT	hu_max_prims_cell;		/* Max # of prims per cell.	     */
INT	hu_gridsize;			/* Grid size.			     */
INT	hu_numbuckets;			/* Hash table bucket size.	     */
INT	hu_max_subdiv_level;		/* Maximum level of hierarchy.	     */
INT	hu_lazy;			/* Lazy evaluation indicator.	     */

INT	prim_obj_cnt;			/* Totals for model.		     */
INT	prim_elem_cnt;
INT	subdiv_cnt;
INT	bintree_cnt;

INT	grids;
INT	total_cells;
INT	empty_voxels;
INT	nonempty_voxels;
INT	nonempty_leafs;
INT	prims_in_leafs;

INT	DataType;
CHAR	GeoFileName[80];		/* Geometry file name.		     */
CHAR	PicFileName[80];		/* Picture file name.		     */
UINT	empty_masks[sizeof(UINT)*8];
UINT	nonempty_masks[sizeof(UINT)*8];

#define PEG_THREADS_TO_CORES

/*
 * NAME
 *	Usage - print proper usage message
 *
 * SYNOPSIS
 *	VOID	Usage()
 *
 * RETURNS
 *	Nothing.
 */

VOID	Usage()
{
    fprintf(stdout, "%s - parallel ray tracer\n", ProgName);
    fprintf(stdout, "Version %s\n\n", VERSION);

    fprintf(stdout, "Usage:\t%s [options] envfile\n\n", ProgName);

    fprintf(stdout, "\t-h\tPrint this usage message.\n");
    fprintf(stdout, "\t-a<n>\tEnable antialiasing with n subpixels (default = 1).\n\tWhen using with SPLASH suite for evaluation, use default (no antialiasing)\n");
    fprintf(stdout, "\t-m<n>\tRequest n megabytes of global memory (default = 32).\n");
    fprintf(stdout, "\t-p<n>\tRun on n processors (default = 1).\n");
    fprintf(stdout, "\t-s\tMeasure and print per-process timing information.\n");
    fprintf(stdout, "\n");
}



/*
 * NAME
 *	PrintStatistics - print out various ray tracer statistics
 *
 * SYNOPSIS
 *	VOID	PrintStatistics()
 *
 * RETURNS
 *	Nothing.
 */

VOID	PrintStatistics()
{
    /*
    printf("\n****** Ray trace Stats ******\n");

    printf("\tResolution:\t\t%ld by %ld\n",            Display.xres+1, Display.yres+1);
    printf("\tNumber Lights:\t\t%ld\n",                nlights);
    printf("\tAnti level:\t\t%ld\n",                   Display.maxAAsubdiv);
    printf("\tTotal Rays:\t\t%ld\n",                   Stats.total_rays);
    printf("\tPrimary Rays:\t\t%ld\n",                 Stats.prim_rays);
    printf("\tShadow Rays:\t\t%ld\n",                  Stats.shad_rays);
    printf("\tShadow Rays Hit:\t%ld\n",                Stats.shad_rays_hit);
    printf("\tShadow Rays Not Hit:\t%ld\n",            Stats.shad_rays_not_hit);
    printf("\tShadow Coherence Rays:\t%ld\n",          Stats.shad_coherence_rays);
    printf("\tReflective Rays:\t%ld\n",                Stats.refl_rays);
    printf("\tTransmissiveRays:\t%ld\n",               Stats.trans_rays);
    printf("\tAnti-Aliasing Rays:\t%ld\n",             Stats.aa_rays);
    printf("\tBackground Pixels:\t%ld\n",              Stats.coverage);
    printf("\tMax Tree depth reached:\t%ld\n",         Stats.max_tree_depth);
    printf("\tMax # prims tested for a ray:\t%ld\n",   Stats.max_objs_ray);
    printf("\tMax Rays shot for a pixel:\t%ld\n",      Stats.max_rays_pixel);
    printf("\tMax # prims tested for a pixel:\t%ld\n", Stats.max_objs_pixel);
    printf("\n");
    */

    if (TraversalType == TT_HUG)
    {
        /*	prn_ds_stats();
        	prn_tv_stats();     */
        ma_print();
    }
}



/*
 * NAME
 *	StartRayTrace - starting point for all ray tracing proceses
 *
 * SYNOPSIS
 *	VOID	StartRayTrace()
 *
 * RETURNS
 *	Nothing.
 */

VOID	StartRayTrace()
{
    INT	pid = 0;			/* Our internal process id number.   */
    UINT	begin;
    UINT	end;

    /* POSSIBLE ENHANCEMENT: Here's where one might lock processes down
    to processors if need be */

    InitWorkPool(pid);
    InitRayTreeStack(Display.maxlevel, pid);

    /* POSSIBLE ENHANCEMENT:  Here's where one would RESET STATISTICS
    and TIMING if one wanted to measure only the parallel part */

    RayTrace(0);
}


/*
 * NAME
 *	main - mainline for the program
 *
 * SYNOPSIS
 *	INT	main(argc, argv)
 *	INT	argc;
 *	CHAR	*argv[];
 *
 * DESCRIPTION
 *	Main parses command line arguments, opens/closes the files involved,
 *	performs initializations, reads in the model database, partitions it
 *	as needed, and calls StartTraceRay() to do the work.
 *
 * RETURNS
 *	0 if successful.
 *	1 for any type of failure.
 */

int	main(int argc, CHAR *argv[])
{
    INT	i;
    UINT	begin;
    UINT	end;
    UINT	lapsed;
    MATRIX	vtrans, Vinv;		/*  View transformation and inverse. */
    struct Timer timer;
    Char8 * dspExecutable    = NULL ;
    char* BufferSize    = NULL ;


    /*
     *	First, process command line arguments.
     */
    printf( "++++++++ First process command line arguments, argc = %d ++++++++\n", argc );
    i = 1;
    while ((i < argc-1) && (argv[i][0] == '-'))
    {
        printf( "Command line argument #%d = %s!\n", i, argv[i] );
        switch (argv[i][1])
        {
        case '?':
        case 'h':
        case 'H':
            Usage();
            exit(1);

        case 'a':
        case 'A':
            AntiAlias = TRUE;

            if (argv[i][2] != '\0')
            {
                NumSubRays = atoi(&argv[i][2]);
            }
            else
            {
                NumSubRays = atoi(&argv[++i][0]);
            }
            printf( "AntiAlias = %d, NumSubRays = %d!\n", TRUE, NumSubRays );
            break;
        case 'm':
            if (argv[i][2] != '\0')
            {
                MaxGlobMem = atoi(&argv[i][2]);
            }
            else
            {
                MaxGlobMem = atoi(&argv[++i][0]);
            }
            break;

        case 'p':
            if (argv[i][2] != '\0')
            {
                nprocs = atoi(&argv[i][2]);
            }
            else
            {
                nprocs = atoi(&argv[++i][0]);
            }
            break;

        case 's':
        case 'S':
            dostats = TRUE;
            break;

        default:
            fprintf(stderr, "%s: Invalid option \'%c\'.\n", ProgName, argv[i][0]);
            exit(1);
        }
        i++;
    }

    if (i == argc-2)
    {
        Usage();
        exit(1);
    }


    nprocs = 1;

    /*
     *	Print command line parameters.
     */

    printf("\n");
    printf("Number of processors:     \t%ld\n", nprocs);
    printf("Global shared memory size:\t%ld MB\n", MaxGlobMem);
    printf("Samples per pixel:        \t%ld\n", NumSubRays);
    printf("\n");


    /*
     *	Initialize the shared memory environment and request the total
     *	amount of amount of shared memory we might need.  This
     *	includes memory for the database, grid, and framebuffer.
     */

    MaxGlobMem <<= 20;			/* Convert MB to bytes.      */
    {
        ;
    }
    gm = (GMEM *)valloc(sizeof(GMEM));;


    /*
     *	Perform shared environment initializations.
     */

    gm->nprocs = nprocs;
    gm->pid    = 0;
    gm->rid    = 1;

    unsigned long	Error;

    /* POSSIBLE ENHANCEMENT:  Here is where one might distribute the
       raystruct data structure across physically distributed memories as
       desired.  */

    if (!GlobalHeapInit(MaxGlobMem))
    {
        fprintf(stderr, "%s: Cannot initialize global heap.\n", ProgName);
        exit(1);
    }


    /*
     *	Initialize HUG parameters, read environment and geometry files.
     */

    Huniform_defaults();
    printf( "ReadEnvFile argv[%d]=%s!\n", i, argv[i] );
    ReadEnvFile(/* *argv*/argv[i]);
    ReadGeoFile(GeoFileName);
    OpenFrameBuffer();


    /*
     *	Compute view transform and its inverse.
     */

    CreateViewMatrix();
    MatrixCopy(vtrans, View.vtrans);
    MatrixInverse(Vinv, vtrans);
    MatrixCopy(View.vtransInv, Vinv);


    /*
     *	Print out what we have so far.
     */

    printf("Number of primitive objects: \t%ld\n", prim_obj_cnt);
    printf("Number of primitive elements:\t%ld\n", prim_elem_cnt);

    /*
     *	Preprocess database into hierarchical uniform grid.
     */

    if (TraversalType == TT_HUG)
        BuildHierarchy_Uniform();

    // set up communication with the DSP.
    
    i++;
    dspExecutable    = argv[i];
    if (dspExecutable == NULL)
    {
        Usage();
        exit(1);
    }   
    printf( "dspExecutable argv[%d]=%s!\n", i, argv[i] );
    
    i++;
    
    BufferSize    = argv[i];
    if (BufferSize == NULL)
    {
        Usage();
        exit(1);
    } 
    printf( "maxStrBufferSize =%s!\n", argv[i] );
    
    if (! pool_notify_Main(dspExecutable, BufferSize))
    {
        printf( "failed to create the pool\n");
        exit(1);
    }
    
    

    /*
     *	Now create slave processes.
     */

    startTimer(&timer);

    StartRayTrace();

    stopTimer(&timer);
    printf( "Time taken = %g ms.\n", getTime_ms(&timer) );

    /*
     *	We are finished.  Clean up, print statistics and run time.
     */

    CloseFrameBuffer(PicFileName);
    PrintStatistics();

    lapsed = (end - begin) & 0x7FFFFFFF;

    printf("TIMING STATISTICS MEASURED BY MAIN PROCESS:\n");
    printf("        Overall start time     %20lu\n", begin);
    printf("        Overall end time   %20lu\n", end);
    printf("        Total time with initialization  %20lu\n", lapsed);
    printf("        Total time without initialization  %20lu\n", end - gm->par_start_time);

    if (dostats)
    {
        unsigned totalproctime, maxproctime, minproctime;

        printf("\n\n\nPER-PROCESS STATISTICS:\n");

        printf("%20s%20s\n","Proc","Time");
        printf("%20s%20s\n\n","","Tracing Rays");
        for (i = 0; i < gm->nprocs; i++)
            printf("%20ld%20ld\n",i,gm->partime[i]);

        totalproctime = gm->partime[0];
        minproctime = gm->partime[0];
        maxproctime = gm->partime[0];

        for (i = 1; i < gm->nprocs; i++)
        {
            totalproctime += gm->partime[i];
            if (gm->partime[i] > maxproctime)
                maxproctime = gm->partime[i];
            if (gm->partime[i] < minproctime)
                minproctime = gm->partime[i];
        }
        printf("\n\n%20s%20d\n","Max = ",maxproctime);
        printf("%20s%20d\n","Min = ",minproctime);
        printf("%20s%20d\n","Avg = ",(int) (((double) totalproctime) / ((double) (1.0 * gm->nprocs))));
    }

    {
        exit(0);
    }
}